import math
from functools import partial

from PyQt6.QtCore import QObject, pyqtSignal, QThread, QTimer, Qt
from PyQt6.QtWidgets import QMainWindow, QGroupBox, QLineEdit, QToolBar, QHBoxLayout, QToolButton, QVBoxLayout, \
    QGridLayout, QWidget, QLabel, QFormLayout, QSizePolicy, QFileDialog, QMessageBox
from PyQt6.QtGui import QIcon, QPainter, QPixmap
from PyQt6 import QtGui, QtCore, uic, QtWidgets

from back.jointWell.main import jointWellDiagram
from front.actions.history import setHistory, get_history
from front.components.progress import Window as Progress
from front.actions.setting import update_setting
from front.actions.showImage import show_image
from front.components.historyJointWell import Window as HistoryJointWell
from utils.error import getError, getError2
from utils.index import resource_path

# 需要注意窗口使用的是Widget还是QMainWidget类
def select_file(lineEdit, fileType="(*)"):
    fd: QFileDialog = QFileDialog()
    fd.setNameFilter(fileType)  # 设置只选择图片文件
    if fd.exec():  # 执行
        lineEdit.setText(fd.selectedFiles()[0])

# 创建线程安全的进度条包装器，用于跨线程传递进度更新
class ProgressBarWrapper(QObject):
    update_progress = pyqtSignal(int)  # 进度更新信号

    def setValue(self, value):
        self.update_progress.emit(value)  # 将值通过信号发送

# 工作线程类
class WorkerThread(QThread):
    # 新增错误信号，携带异常信息字典
    error_occurred = pyqtSignal(dict)
    finished_success = pyqtSignal()  # 成功完成信号

    def __init__(self, params, progress_wrapper):
        super().__init__()
        self.params = params
        self.progress_wrapper = progress_wrapper

    def run(self):
        try:
            # 在线程中执行耗时操作，通过包装器更新进度
            jointWellDiagram(self.params, self.progress_wrapper)
            self.finished_success.emit()  # 任务成功完成
        except Exception as e:
            # 捕获异常并通过信号传递
            self.error_occurred.emit(getError2(2))

class JointWellWindow(QMainWindow):
    def __init__(self, well_num):
        super().__init__()
        self.ui = uic.loadUi(resource_path("static/ui/jointWell.ui"), self)  # 加载主窗口的 UI 文件
        self.params = {
            "wellnum": None,  # 联井数
            # 输出文件
            "outfile": None,  # 文件名
            # 地面文件
            "seisdata": None,  # 文件名
            "trange": None,  # 时间范围
            # 滤波走廊
            "wellname1": None,  # 井名
            "welldata1": None,  # 井数据
            "wellfc1": None,  # 井层位标定表
            "wellts1": None,
            "welllrnum1": None,
            "wellstep1": None,
            # 设置
            "tpi": None,  # 深度比例尺
            "ips": None,  # 时间比例尺
            "agc": None,  # 增益时窗
            "fcxc": None,  # 分层线的长度
            "colour": None,  # rgb
            "opacity": None,
            "lineweight": None,
            "fontsize": None
        } # 参数列表
        self.errMsgs = []  # 错误信息
        self.well_num = int(well_num)
        self.module_name = "联井标定"
        self.e_name = "joint_well"  # 历史记录文件中的属性名
        self.elem = []  # 存放控件，每个数据项都是一个obj，每个obj都保存了well的相关属性
        self.group_box = []  # 存放group_box
        self.init_style()  # 初始化样式
        self.init_elem()  # 初始化页面控件，创建well控件，设置页面布局
        self.init_params()  # 初始化参数
        self.init_event()  # 初始化事件

    # ========================================================
    # 重写方法
    # ========================================================

    # 在 paintEvent 中绘制背景图片
    def paintEvent(self, event):
        painter = QPainter(self)
        pixmap = QPixmap(resource_path("static/image/bg2Cut.png"))
        painter.drawPixmap(self.rect(), pixmap)  # 使用 pixmap 填充整个窗口

    # 根据窗口宽度动态调整
    def resizeEvent(self, event):
        # 获取窗口当前宽度
        width = self.width()
        # 根据窗口宽度动态调整字体大小
        fontSize = int(width / 150)
        if fontSize < 10:
            fontSize = 10
        if fontSize > 18:
            fontSize = 18

        # 定义一个递归函数来遍历所有子控件，并设置字体大小
        def traverse_widgets(widget):
            if hasattr(widget, 'setFont'):
                font = widget.font()
                font.setPointSize(fontSize)
                widget.setFont(font)
            for child in widget.children():
                traverse_widgets(child)

        # 从主窗口开始遍历所有控件
        traverse_widgets(self)

        # 设置groupBox的内边距
        groupBoxes = self.findChildren(QGroupBox)
        for groupBox in groupBoxes:
            groupBox.setContentsMargins(fontSize, fontSize * 2, fontSize, fontSize)

        super().resizeEvent(event)

    # ========================================================
    # 初始化
    # ========================================================

    # 设置窗口图标和标题
    def init_style(self):
        self.ui.setWindowTitle(f"SeismicPlot-{self.module_name}")
        self.ui.setWindowIcon(QIcon(resource_path('static/image/favicon.ico')))
        self.resize(1200, 670)  # 设置窗口大小
        # 设置工具栏
        self.run_action = self.ui.toolBar.addAction(QtGui.QIcon(resource_path("static/image/run.png")), "运行")
        self.ui.toolBar.addSeparator()  # 分隔线
        self.reset_action = self.ui.toolBar.addAction(QtGui.QIcon(resource_path("static/image/reset.png")), "重置")
        self.ui.toolBar.addSeparator()
        self.view_image_action = self.ui.toolBar.addAction(QtGui.QIcon(resource_path("static/image/img.png")), "查看出图")
        self.ui.toolBar.addSeparator()
        self.history_action = self.ui.toolBar.addAction(QtGui.QIcon(resource_path("static/image/history.png")), "历史记录")
        self.ui.toolBar.addSeparator()
        self.setting_action = self.ui.toolBar.addAction(QtGui.QIcon(resource_path("static/image/setting.png")), "设置")
        self.ui.addToolBar(QtCore.Qt.ToolBarArea.LeftToolBarArea, self.ui.toolBar)

    # 初始化页面元素，创建元素，并设置布局
    def init_elem(self):
        self.elem = []  # 存放元素
        self.group_box = []  # 存放groupbox
        col = 0  # 列
        row = 0  # 行

        self.ui.gridLayout.addWidget(self.ui.groupBox, 0, 0, 4, 1)  # 输出文件
        self.ui.gridLayout.addWidget(self.ui.groupBox_3, 4, 0, 5, 1)  # 地面文件

        for i in range(self.well_num):
            elem_result = self.create_elem(i)  # 创建元素
            self.elem.append(elem_result["elem"])
            self.group_box.append(elem_result["group_box"])

            col = math.ceil(i / 2) # 列，从1开始
            row = int(math.fabs(i % 2 - 1))  # 行，1，2的倍数，0非2的倍数
            if i == 0:  # 井
                self.ui.gridLayout.addWidget(elem_result["group_box"], 9, 0, 7, 1)
            else:
                self.ui.gridLayout.addWidget(elem_result["group_box"], row * 8, col, 8, 1)

        if row == 0:  # 设置
            self.ui.gridLayout.addWidget(self.ui.groupBox_9, 8, col, 8, 1)
        else:
            col = col + 1
            self.ui.gridLayout.addWidget(self.ui.groupBox_9, 0, col, 8, 1)

        # 设置列的拉伸因子，使列平均分配空间
        for j in range(col + 1):
            print(j)
            self.ui.gridLayout.setColumnStretch(j, 1)

        # # 强制窗口和布局更新
        self.ui.update()

    # 创建页面元素
    def create_elem(self, index):
        elem_group = {
            # 井名
            "label1": QLabel(),
            "line_edit1": QLineEdit(),
            # 井数据
            "label6": QLabel(),
            "line_edit6": QLineEdit(),
            "toolButton6": QToolButton(),
            # 井层位标定
            "label2": QLabel(),
            "line_edit2": QLineEdit(),
            "toolButton2": QToolButton(),
            # wellts
            "label3": QLabel(),
            "line_edit3": QLineEdit(),
            # welllrnum
            "label4": QLabel(),
            "line_edit4": QLineEdit(),
            # wellstep
            "label5": QLabel(),
            "line_edit5": QLineEdit(),
        }

        # 创建表单布局
        form_layout_100 = QFormLayout()  # 表单布局
        form_layout_100.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)  # 对齐

        # 井名
        elem_group["label1"].setText('井名')
        form_layout_100.addRow(elem_group["label1"], elem_group["line_edit1"])

        # 井数据
        elem_group["toolButton6"].setText('...')
        horizontal_layout2 = QHBoxLayout()
        horizontal_layout2.addWidget(elem_group["line_edit6"])
        horizontal_layout2.addWidget(elem_group["toolButton6"])
        horizontal_layout2.setContentsMargins(0, 0, 0, 0)  # 去除容器内部边距
        container_3 = QWidget()
        container_3.setLayout(horizontal_layout2)
        elem_group["label6"].setText('井数据')
        form_layout_100.addRow(elem_group["label6"], container_3)

        # 井层位标定表
        elem_group["toolButton2"].setText('...')
        horizontal_layout = QHBoxLayout()
        horizontal_layout.addWidget(elem_group["line_edit2"])
        horizontal_layout.addWidget(elem_group["toolButton2"])
        horizontal_layout.setContentsMargins(0, 0, 0, 0)  # 去除容器内部边距
        container_2 = QWidget()
        container_2.setLayout(horizontal_layout)
        elem_group["label2"].setText('井层位标定表')
        form_layout_100.addRow(elem_group["label2"], container_2)

        # wellts
        elem_group["label3"].setText('wellts')
        form_layout_100.addRow(elem_group["label3"], elem_group["line_edit3"])

        # welllrnum
        elem_group["label4"].setText('welllrnum')
        form_layout_100.addRow(elem_group["label4"], elem_group["line_edit4"])

        # wellstep
        elem_group["label5"].setText('wellstep')
        form_layout_100.addRow(elem_group["label5"], elem_group["line_edit5"])

        # 创建 QGroupBox
        group_box_100 = QGroupBox(f'well{index + 1}')
        group_box_100.setLayout(form_layout_100)

        # 确保表单的右侧部分按照最大标签长度分配空间
        form_layout_100.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)

        return {
            "elem": elem_group,
            "group_box": group_box_100
        }

    # 初始化参数
    def init_params(self):
        # 输出文件
        self.ui.lineEdit.setText("")  # 文件名
        # 地面文件
        self.ui.lineEdit_3.setText("")  # 文件名
        self.ui.lineEdit_6.setText("")  # 时间绘制范围-开始
        self.ui.lineEdit_4.setText("")  # 时间绘制范围-结束
        # well
        for i in range(len(self.elem)):
            self.elem[i]["line_edit1"].setText("")  # 井名
            self.elem[i]["line_edit6"].setText("")  # 井数据
            self.elem[i]["line_edit2"].setText("")  # 井层位标定表
            self.elem[i]["line_edit3"].setText("0")  # wellts
            self.elem[i]["line_edit4"].setText("10")  # welllrnum
            self.elem[i]["line_edit5"].setText("1")  # wellstep
        # 设置
        self.ui.lineEdit_27.setText("12")  # 深度比例尺
        self.ui.lineEdit_28.setText("10")  # 时间比例尺
        self.ui.lineEdit_35.setText("500")  # 时窗
        self.ui.lineEdit_36.setText("100")  # 分层线长度
        self.ui.lineEdit_30.setText("0")  # colour
        self.ui.lineEdit_37.setText("0")  # colour
        self.ui.lineEdit_38.setText("0")  # colour
        self.ui.lineEdit_31.setText("1.0")  # opacity
        self.ui.lineEdit_32.setText("0.4")  # lineweight
        self.ui.lineEdit_33.setText("13")  # fontsize

    # 给控件绑定事件
    def init_event(self):
        pass
        # 给文件选择按钮绑定事件
        self.ui.toolButton.clicked.connect(lambda: select_file(self.ui.lineEdit, "(*.png *.bmp)"))  # 输出文件
        self.ui.toolButton_3.clicked.connect(lambda: select_file(self.ui.lineEdit_3, "(*.sgy)"))  # 地面文件
        for i in range(len(self.elem)):
            # 使用partial方法，解决闭包问题
            self.elem[i]["toolButton6"].clicked.connect(partial(select_file, self.elem[i]["line_edit6"], "(*.sgy)"))
            self.elem[i]["toolButton2"].clicked.connect(partial(select_file, self.elem[i]["line_edit2"], "(*.xlsx *.xls)"))

        # 给工具栏按钮绑定事件
        self.run_action.triggered.connect(self.run)  # 运行
        self.reset_action.triggered.connect(self.init_params)  # 重置
        self.view_image_action.triggered.connect(lambda : show_image(self))  # 查看出图
        self.history_action.triggered.connect(lambda: get_history(self, HistoryJointWell))  # 历史记录
        self.setting_action.triggered.connect(lambda : update_setting(self))  # 设置

    def load_params(self, obj):
        data = obj["data"]
        # 删除页面中的groupbox，即well的数据
        for i in range(len(self.group_box)):
            self.ui.gridLayout.removeWidget(self.group_box[i])  # 移除 QGroupBox 从主布局中
            self.group_box[i].deleteLater()  # 删除 QGroupBox 及其内部的所有控件

        self.well_num = data["wellnum"]  # 联井数
        self.init_elem()  # 重新生成页面控件

        # 输出文件
        self.ui.lineEdit.setText(f"{data['outfile']}")  # 文件名
        # 地面文件
        self.ui.lineEdit_3.setText(f"{data['seisdata']}")  # 文件名
        self.ui.lineEdit_6.setText(f"{data['trange'][0]}")  # 时间绘制范围-开始
        self.ui.lineEdit_4.setText(f"{data['trange'][1]}")  # 时间绘制范围-结束
        # well
        for i in range(self.well_num):
            self.elem[i]["line_edit1"].setText(f"{data[f'wellname{i + 1}']}")  # 井名
            self.elem[i]["line_edit6"].setText(f"{data[f'welldata{i + 1}']}")  # 井数据
            self.elem[i]["line_edit2"].setText(f"{data[f'wellfc{i + 1}']}")  # 井层位标定表
            self.elem[i]["line_edit3"].setText(f"{data[f'wellts{i + 1}']}")  # wellts
            self.elem[i]["line_edit4"].setText(f"{data[f'welllrnum{i + 1}']}")  # welllrnum
            self.elem[i]["line_edit5"].setText(f"{data[f'wellstep{i + 1}']}")  # wellstep
        # 设置
        self.ui.lineEdit_27.setText(f"{data['tpi']}")  # 拉平宽度
        self.ui.lineEdit_28.setText(f"{data['ips']}")  # 高度
        self.ui.lineEdit_35.setText(f"{data['agc']}")  # agc
        self.ui.lineEdit_36.setText(f"{data['fcxc']}")  # 分层线长度
        self.ui.lineEdit_30.setText(f"{data['colour'][0]}")  # colour
        self.ui.lineEdit_37.setText(f"{data['colour'][1]}")  # colour
        self.ui.lineEdit_38.setText(f"{data['colour'][2]}")  # colour
        self.ui.lineEdit_31.setText(f"{data['opacity']}")  # opacity
        self.ui.lineEdit_32.setText(f"{data['lineweight']}")  # lineweight
        self.ui.lineEdit_33.setText(f"{data['fontsize']}")  # fontsize

    # ========================================================
    # 获取参数
    # ========================================================

    # 获取参数
    def get_params(self):
        self.errMsgs = []  # 重置错误信息
        # 联井数
        self.params["wellnum"] = self.well_num
        # 输出文件
        self.params["outfile"] = self.get_file(self.ui.lineEdit, "输出文件|文件名")
        # 地面文件
        self.params["seisdata"] = self.get_file(self.ui.lineEdit_3, "地面文件|文件名")
        self.params["trange"] = []  # 时间绘制范围
        self.params["trange"].append(self.get_line_edit_value(self.ui.lineEdit_6, "地面文件|时间绘制范围（开始）"))
        self.params["trange"].append(self.get_line_edit_value(self.ui.lineEdit_4, "地面文件|时间绘制范围（结束）"))
        # 滤波走廊
        for i in range(len(self.elem)):
            self.params[f"wellname{i + 1}"] = self.get_well_name(self.elem[i]["line_edit1"], f"well{i + 1}|井名")
            self.params[f"welldata{i + 1}"] = self.get_file(self.elem[i]["line_edit6"], f"well{i + 1}|井数据")
            self.params[f"wellfc{i + 1}"] = self.get_file(self.elem[i]["line_edit2"], f"well{i + 1}|井层位标定表")
            self.params[f"wellts{i + 1}"] = self.get_line_edit_value(self.elem[i]["line_edit3"], f"well{i + 1}|wellts", "int")
            self.params[f"welllrnum{i + 1}"] = self.get_line_edit_value(self.elem[i]["line_edit4"], f"well{i + 1}|welllrnum", "int")
            self.params[f"wellstep{i + 1}"] = self.get_line_edit_value(self.elem[i]["line_edit5"], f"well{i + 1}|wellstep", "int")
        # 设置
        self.params["tpi"] = self.get_line_edit_value(self.ui.lineEdit_27, "设置|深度比例尺", "int")
        self.params["ips"] = self.get_line_edit_value(self.ui.lineEdit_28, "设置|时间比例尺", "int")
        self.params["agc"] = self.get_line_edit_value(self.ui.lineEdit_28, "设置|增益时窗", "int")
        self.params["fcxc"] = self.get_line_edit_value(self.ui.lineEdit_28, "设置|分层线的长度", "int")
        self.params["colour"] = []
        self.params["colour"].append(self.get_line_edit_value(self.ui.lineEdit_30, "设置|colour-r", "int"))
        self.params["colour"].append(self.get_line_edit_value(self.ui.lineEdit_37, "设置|colour-g", "int"))
        self.params["colour"].append(self.get_line_edit_value(self.ui.lineEdit_38, "设置|colour-b", "int"))
        self.params["opacity"] = self.get_line_edit_value(self.ui.lineEdit_31, "设置|opacity")
        self.params["lineweight"] = self.get_line_edit_value(self.ui.lineEdit_32, "设置|lineweight")
        self.params["fontsize"] = self.get_line_edit_value(self.ui.lineEdit_33, "设置|fontsize", "int")
        print(self.params)
        if len(self.errMsgs) != 0:
            QMessageBox.warning(self, self.errMsgs[0][0], self.errMsgs[0][1])
            return False
        return True

    def get_file(self, lineEdit, msg):
        text = lineEdit.text()
        if text:
            return text
        else:
            self.errMsgs.append(["输入错误", f"[{msg}]不能为空，请输入正确的文件路径！"])

    """
    获取数据输入框中的值，根据numType的值进行数据类型的转换

    Args:
        lineEdit (QlineEdit): QlineEdit对象
        msg (string): 错误弹窗提示信息
        numType (string): 目标数据类型，默认'float'

    Returns:


    Raises:


    Example:
        >>> add_numbers(self.ui.lineEdit_30, "其他|colour-r", "int")
    """
    def get_line_edit_value(self, lineEdit, msg, numType='float'):
        text = lineEdit.text()
        if text:
            try:
                if numType == 'float':
                    return float(text)
                else:
                    return int(text)
            except ValueError:
                self.errMsgs.append(["输入错误", f"[{msg}]输入错误，请输入有效的数字！"])
        else:
            self.errMsgs.append(["输入错误", f"[{msg}]输入不能为空，请输入有效的数字！"])

    def get_well_name(self, lineEdit, msg):
        text = lineEdit.text()
        if text:
            return str(text)
        else:
            self.errMsgs.append(["输入错误", f"[{msg}]输入不能为空，请输入有效的井名！"])

    # ========================================================
    # 运行
    # ========================================================

    # 运行，出图
    def run(self):
        if self.get_params():  # 获取参数，且当参数没有问题时调用bridgeDiagram
            try:
                # 在界面初始化部分修改如下
                self.ui.progressbar = Progress()  # 进度条
                self.ui.progressbar.show()

                # 创建线程安全的进度包装器并连接信号
                self.progress_wrapper = ProgressBarWrapper()
                self.progress_wrapper.update_progress.connect(self.ui.progressbar.start_progress)

                # 创建并启动工作线程
                self.worker_thread = WorkerThread(self.params, self.progress_wrapper)
                self.worker_thread.start()

                # 事件处理，当执行错误触发时，也会触发finished，所以改为finished_success
                # self.worker_thread.finished.connect(self.handle_thread_success)  # 完成时触发
                self.worker_thread.finished_success.connect(self.handle_thread_success)  # 执行成功时触发
                self.worker_thread.error_occurred.connect(self.handle_thread_error)  # 执行错误时触发
            except:
                # 这里只能捕获主线程初始化阶段的错误
                err = getError()
                QMessageBox.warning(self, f"{err['type']}",
                                    f"{err['msg']}, file in {err['file']}, line in {err['line']}.")


    # 运行错误处理函数
    def handle_thread_error(self, err):
        self.ui.progressbar.close()  # 关闭进度条，发生错误时需要手动关闭进度条
        QMessageBox.warning(self, f"{err['type']}",
                            f"{err['msg']}, file in {err['file']}, line in {err['line']}, \n {err['code']}.")
        # 保存历史记录
        setHistory(self, "error")

    # 运行成功处理函数
    def handle_thread_success(self):
        QMessageBox.information(self, 'SeismicPlot-桥图', '出图成功', QMessageBox.StandardButton.Ok)
        # 保存历史记录
        setHistory(self, "success")